﻿// GetKeyboardLayoutName.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <windows.h>
#include <vector>
#include <string>
#include <fcntl.h>
#include <iostream>
#include <io.h>
struct layout
{
	layout(const wchar_t* _id, const wchar_t * t) :text(t)
	{
		for (int i = 0; i < lstrlen(_id); i++)
		{
			id[i] = toupper(_id[i]);
		}
		id[4] = '\0';
	}

	wchar_t id[5];
	std::wstring text;
};
std::vector<layout> layoutArray;

int findLayout(const wchar_t*_id)
{

	for (int i = 0; i < layoutArray.size(); ++i)
	{
		if (0 == lstrcmp(layoutArray[i].id, _id))
		{
			return i;
		}
	}
	return -1;
}
int getLayoutText(WORD id, wchar_t* buffer, int buf_len)
{
	wsprintf(buffer, L"%04X", id);

	int layout = findLayout(buffer);

	if (buffer == NULL && buf_len == 0 && layout != -1)
	{
		return layoutArray[layout].text.length();
	}

	if (layout != -1)
	{
		lstrcpy(buffer, layoutArray[layout].text.c_str());
		return layoutArray[layout].text.length();
	}
	return 0;
}

bool initLayoutListFromRegister()
{
	layoutArray.clear();
	HKEY hKey = 0;
	RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"system\\currentcontrolset\\control\\keyboard layouts", 0, KEY_READ, &hKey);
	wchar_t keyName[1024];
	wchar_t className[1024];

	for (int i = 0; ; i++)
	{
		FILETIME ft = { 0 };
		DWORD dwSubkeyNameSize = sizeof(wchar_t)* 1024;
		ZeroMemory(keyName, sizeof(wchar_t)* 1024);
		ZeroMemory(className, sizeof(wchar_t)* 1024);
		LSTATUS status = RegEnumKeyEx(hKey, i, keyName, &dwSubkeyNameSize, 0, 0, 0, &ft);
		wchar_t monid[] = L"850";

		if (status == ERROR_NO_MORE_ITEMS)
		{
			break;
		}
		int start = lstrlen(keyName) - 3;
		int sizeofmonid = sizeof(monid);
		int size = sizeof(monid)* sizeof(wchar_t);
		if (0 == memcmp(&keyName[start], monid, 6))
		{
			HKEY hSubKey = 0;
			std::wstring subkey = L"system\\currentcontrolset\\control\\keyboard layouts\\";
			subkey.append(keyName);
			wprintf(L"%s\r\n", keyName);
			wchar_t valuename[1024];

			DWORD type = 0;
			byte data[1024];

			RegCreateKeyEx(HKEY_LOCAL_MACHINE, subkey.c_str(), 0, 0, 0, KEY_READ, 0, &hSubKey, 0);
			wchar_t layout_id[5] = { 0 };
			std::wstring layout_text;
			for (int j = 0;; j++)
			{
				DWORD sizeofvaluename = 1024;
				DWORD datalen = 1024;
				valuename[0] = '\0';
				ZeroMemory(data, 1024);
				LSTATUS status2 = RegEnumValue(hSubKey, j, valuename, &sizeofvaluename, 0, &type, data, &datalen);
				if (status2 == ERROR_NO_MORE_ITEMS)
				{
					if (lstrlen(layout_id) > 0)
					{
						layoutArray.emplace_back(layout_id, layout_text.c_str());
					}
					break;
				}

				if (REG_SZ == type || REG_EXPAND_SZ == type)
				{
					wchar_t buffer[1024];
					wchar_t *dataw = (wchar_t*)data;
					wsprintf(buffer, L"%s = %s\r\n", valuename, dataw);

					OutputDebugString(buffer);
					wprintf(L"%s", buffer);

					if (0 == lstrcmp(valuename, L"Layout Id"))
					{
						lstrcpy(layout_id, dataw);
					}
					if (0 == lstrcmp(valuename, L"Layout Text"))
					{
						layout_text = dataw;
					}
				}



			}


		}

	}
}
int _tmain(int argc, _TCHAR* argv[])
{


	char bom1 = (char)0xff;
	char bom2 = (char)0xfe;

	printf("%c%c", bom1, bom2);



	//
	//http://stackoverflow.com/questions/2492077/output-unicode-strings-in-windows-console-app
	//
	_setmode(_fileno(stdout), _O_U16TEXT);

	//wprintf(L"%s", L"日本語\r\n");


	initLayoutListFromRegister();


	//

	for (int i = 0; i < layoutArray.size(); i++)
	{
		wprintf(L"Layout Text=%s, Layout Text=%s\r\n", layoutArray[i].id, layoutArray[i].text.c_str());
	}
	//
	int count = GetKeyboardLayoutList(0, 0);
	HKL *kbList = new  HKL[count];
	count = GetKeyboardLayoutList(count, kbList);
	for (int i = 0; i < count; i++)
	{
		WORD layoutID = 0;
		WORD hi = HIWORD(kbList[i]);
		WORD hi_and_F000 = hi & 0xF000;
		if ((hi & 0xF000) == 0xF000)
			layoutID = hi & 0x0FFF;
		wchar_t buffer[1024] = {0};
		getLayoutText(layoutID, buffer, 1024);
		wprintf(L"HKL=%08X, Hi=%04X, Lo=%04X, layoutID=%04X, Layout Text=%s\r\n", kbList[i], hi, LOWORD(kbList[i]), layoutID, buffer);
	}
	delete[] kbList;
	return 0;
}

